#ifndef __IVARIANT_IMPL_H__
#define __IVARIANT_IMPL_H__

#include "co_class_base.h"
#include "ref_obj_ptr.h"
#include "ibase_impl.h"

#include <vector>


namespace Boss
{

  class IVariantImpl
    : public CoClassBase
        <
          TL::TypeListAdapter
            <
              IVariant
            >
        >
  {
  public:
    BOSS_DECLARE_CLSID(0b9550da-6466-4fd4-9a43-40901551f727)

      IVariantImpl()
    {
    }
    virtual ~IVariantImpl()
    {
    }

    // IVariant
    virtual TResult BOSS_CALL_TYPE SetValue(VariantType type, const TPtr value)
    {
      ISyncObject Lock(GetSynObj());
      switch (type)
      {
      case vtUnknown :
        Holder.reset(0);
        break;
      case vtBool :
        Holder.reset(new IVariantHolderSimple<bool, vtBool>(*reinterpret_cast<const bool *>(value)));
        break;
      case vtIBase :
        Holder.reset(new IVariantHolderIBase(reinterpret_cast<IBase *>(value)));
        break;
      case vtChar :
        Holder.reset(new IVariantHolderSimple<char, vtChar>(*reinterpret_cast<const char *>(value)));
        break;
      case vtUChar :
        Holder.reset(new IVariantHolderSimple<unsigned char, vtUChar>(*reinterpret_cast<const unsigned char *>(value)));
        break;
      case vtShort :
        Holder.reset(new IVariantHolderSimple<short, vtShort>(*reinterpret_cast<const short *>(value)));
        break;
      case vtUShort :
        Holder.reset(new IVariantHolderSimple<unsigned short, vtUShort>(*reinterpret_cast<const unsigned short *>(value)));
        break;
      case vtInt :
        Holder.reset(new IVariantHolderSimple<int, vtInt>(*reinterpret_cast<const int *>(value)));
        break;
      case vtUInt :
        Holder.reset(new IVariantHolderSimple<unsigned, vtUInt>(*reinterpret_cast<const unsigned *>(value)));
        break;
      case vtLong :
        Holder.reset(new IVariantHolderSimple<long, vtLong>(*reinterpret_cast<const long *>(value)));
        break;
      case vtULong :
        Holder.reset(new IVariantHolderSimple<unsigned long, vtULong>(*reinterpret_cast<const unsigned long *>(value)));
        break;
      case vtFloat :
        Holder.reset(new IVariantHolderSimple<float, vtFloat>(*reinterpret_cast<const float *>(value)));
        break;
      case vtDouble :
        Holder.reset(new IVariantHolderSimple<double, vtDouble>(*reinterpret_cast<const double *>(value)));
        break;
      case vtString :
        Holder.reset(new IVariantHolderString<char, vtString>(reinterpret_cast<const char *>(value)));
        break;
      case vtWString :
        Holder.reset(new IVariantHolderString<wchar_t, vtWString>(reinterpret_cast<const wchar_t *>(value)));
        break;
      default :
        return rcFail;
      }
      return rcOk;
    }
    virtual TResult BOSS_CALL_TYPE SetBinaryValue(const TPtr value, ULong bytes)
    {
      ISyncObject Lock(GetSynObj());
      Holder.reset(new IVariantHolderBinary(value, bytes));
      return rcOk;
    }
    virtual TResult BOSS_CALL_TYPE GetValue(TPtr *value) const
    {
      ISyncObject Lock(GetSynObj());
      if (!Holder.get())
        return rcFail;
      Holder->GetData(value);
      return rcOk;
    }
    virtual TResult BOSS_CALL_TYPE GetValueSize(ULong *size) const
    {
      if (!size)
        return rcBadParam;
      ISyncObject Lock(GetSynObj());
      *size = !Holder.get() ? 0 : Holder->GetSize();  
      return rcOk;
    }
    virtual TResult BOSS_CALL_TYPE IsEmpty(bool *isEmpty) const
    {
      if (!isEmpty)
        return rcBadParam;
      ISyncObject Lock(GetSynObj());
      *isEmpty = !Holder.get();
      return rcOk;
    }
    virtual TResult BOSS_CALL_TYPE GetType(VariantType *type) const
    {
      if (!type)
        return rcBadParam;
      ISyncObject Lock(GetSynObj());
      *type = Holder.get() ? Holder->GetType() : vtUnknown;
      return rcOk;
    }
    virtual TResult BOSS_CALL_TYPE Clear()
    {
      ISyncObject Lock(GetSynObj());
      Holder.reset(0);
      return rcOk;
    }

  private:
    struct IVariantHolder
    {
      virtual ~IVariantHolder()
      {
      }
      virtual VariantType GetType() const = 0;
      virtual ULong GetSize() const = 0;
      virtual void GetData(TPtr *data) const = 0;
    };
    typedef std::auto_ptr<IVariantHolder> IVariantHolderPtr;
    template <typename TVal, VariantType VarType>
    class IVariantHolderSimple
      : public IVariantHolder
      , private Boss::NonCopyable
    {
    public:
      IVariantHolderSimple(const TVal &val)
        : Val(val)
      {
      }
      virtual VariantType GetType() const
      {
        return VarType;
      }
      virtual ULong GetSize() const
      {
        return sizeof(TVal);
      }
      virtual void GetData(TPtr *data) const
      {
        *data = &Val;
      }
    private:
      mutable TVal Val;
    };
    class IVariantHolderBinary
      : public IVariantHolder
      , private Boss::NonCopyable
    {
    public:
      IVariantHolderBinary(const TPtr val, ULong bytes)
        : Buf(&reinterpret_cast<const char *>(val)[0], &reinterpret_cast<const char *>(val)[bytes])
      {
      }
      virtual VariantType GetType() const
      {
        return vtBinary;
      }
      virtual ULong GetSize() const
      {
        return static_cast<ULong>(Buf.size());
      }
      virtual void GetData(TPtr *data) const
      {
        *data = Buf.empty() ? 0 : &Buf[0];
      }
    private:
      mutable std::vector<char> Buf;
    };
    class IVariantHolderIBase
      : public IVariantHolder
      , private Boss::NonCopyable
    {
    public:
      IVariantHolderIBase(IBase *ptr)
        : Ptr(ptr)
      {
      }
      virtual VariantType GetType() const
      {
        return vtIBase;
      }
      virtual ULong GetSize() const
      {
        return sizeof(IBase *);
      }
      virtual void GetData(TPtr *data) const
      {
        Ptr->QueryInterface(BOSS_UUID_OF(IBase), data);
      }
    private:
      RefObjPtr<IBase> Ptr;
    };
    template <typename TChar, VariantType VarType>
    class IVariantHolderString
      : public IVariantHolder
      , private Boss::NonCopyable
    {
    public:
      IVariantHolderString(const TChar *str)
      {
        for ( ; *str ; ++str)
          Str.push_back(*str);
        Str.push_back(0);
      }
      virtual VariantType GetType() const
      {
        return VarType;
      }
      virtual ULong GetSize() const
      {
        return static_cast<ULong>(sizeof(TChar) * Str.size());
      }
      virtual void GetData(TPtr *data) const
      {
        *data = &Str[0];
      }
    private:
      typedef std::vector<TChar> TString;
      mutable TString Str;
    };

    IVariantHolderPtr Holder;
  };

}

#endif  // !__IVARIANT_IMPL_H__
